package com.qsw.refreshrecyclerview.RefreshRecyclerView.view;

import android.content.Context;
import android.graphics.Rect;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.helper.ItemTouchHelper;
import android.util.AttributeSet;
import android.view.View;

import com.qsw.refreshrecyclerview.RefreshRecyclerView.adapter.HeaderFooterRecyclerAdapter;
import com.qsw.refreshrecyclerview.RefreshRecyclerView.adapter.OnItemTouchHelperCallBack;
import com.qsw.refreshrecyclerview.RefreshRecyclerView.listener.OnItemClickListener;
import com.qsw.refreshrecyclerview.RefreshRecyclerView.listener.OnItemDragListener;
import com.qsw.refreshrecyclerview.RefreshRecyclerView.listener.RecyclerTouchListener;

/**
 * 支持加载更多的RecyclerView
 */
public class RefreshRecyclerView extends RecyclerView {

    // 包裹了一层的头部底部Adapter
    private HeaderFooterRecyclerAdapter mHeaderFooterRecyclerAdapter;

    // 这个是列表数据的Adapter
    private RecyclerView.Adapter mAdapter;

    /**
     * 界面需要加载更多的时候回调
     */
    private OnRefreshListener mOnRefreshListener;
    /**
     * 条目点击事件
     */
    private OnItemClickListener mOnItemClickListener;
    /**
     * 条目拖拽事件
     */
    private OnItemDragListener mOnItemDragListener;

    private boolean mIsLoading; // 是否正在加载

    private boolean mShowFooter; // 是否显示加载状态的页尾

    /**
     * 正在加载的页尾界面
     */
    private int mFooterLoadingViewId;
    /**
     * 正在加载的页尾界面
     */
    private View mFooterLoadingView;
    /**
     * 加载完成没有更多数据的页尾界面
     */
    private int mFooterLoadEndViewId;
    /**
     * 加载完成没有更多数据的页尾界面
     */
    private View mFooterLoadEndView;

    /**
     * 恢复上次位置使用，可见的第一个item索引
     */
    private int mFirstVisiblePosition;
    /**
     * 恢复上次位置使用，可见的第一个item索引偏移量
     */
    private int mFirstVisiblePositionOffset;

    /**
     * 用于拖拽item
     */
    private ItemTouchHelper mItemTouchHelper;

    public RefreshRecyclerView(@NonNull Context context) {
        this(context, null);
    }

    public RefreshRecyclerView(@NonNull Context context, @Nullable AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public RefreshRecyclerView(@NonNull Context context, @Nullable AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        init();
    }

    private void init() {
        LinearLayoutManager manager = new LinearLayoutManager(getContext());
        manager.setOrientation(LinearLayoutManager.VERTICAL);
        setLayoutManager(manager);

        addOnScrollListener(mOnScrollListener);
        addOnItemTouchListener(new RecyclerTouchListener(getContext(), this, mInnerOnItemClickListener));

        mItemTouchHelper = new ItemTouchHelper(mOnItemTouchHelperCallBack);
    }

    @Override
    public void setAdapter(Adapter adapter) {
        // 为了防止多次设置Adapter
        if (mAdapter != null) {
            mAdapter.unregisterAdapterDataObserver(mDataObserver);
            mAdapter = null;
        }

        this.mAdapter = adapter;

        if (adapter instanceof HeaderFooterRecyclerAdapter) {
            mHeaderFooterRecyclerAdapter = (HeaderFooterRecyclerAdapter) adapter;
        } else {
            mHeaderFooterRecyclerAdapter = new HeaderFooterRecyclerAdapter(adapter);
        }

        super.setAdapter(mHeaderFooterRecyclerAdapter);

        // 注册一个观察者
        mAdapter.registerAdapterDataObserver(mDataObserver);

        // 解决GridLayout添加头部和底部也要占据一行
        mHeaderFooterRecyclerAdapter.adjustSpanSize(this);
    }

    public void setDragEnable(boolean enable) {
        if (enable) {
            mItemTouchHelper.attachToRecyclerView(this);
        } else {
            mItemTouchHelper.attachToRecyclerView(null);
        }
    }

    /**
     * 添加头部
     *
     * @param view 头部View
     */
    public void addHeaderView(View view) {
        // 如果没有Adapter那么就不添加，也可以选择抛异常提示
        // 让他必须先设置Adapter然后才能添加，这里是仿照ListView的处理方式
        if (mHeaderFooterRecyclerAdapter != null) {
            mHeaderFooterRecyclerAdapter.addHeaderView(view);
        }
    }

    /**
     * 添加头部
     *
     * @param viewId 头部ViewId
     */
    public void addHeaderView(int viewId) {
        // 如果没有Adapter那么就不添加，也可以选择抛异常提示
        // 让他必须先设置Adapter然后才能添加，这里是仿照ListView的处理方式
        if (mHeaderFooterRecyclerAdapter != null) {
            mHeaderFooterRecyclerAdapter.addHeaderView(viewId);
        }
    }

    /**
     * 移除头部
     *
     * @param view 头部View
     */ // 移除头部
    public void removeHeaderView(View view) {
        if (mHeaderFooterRecyclerAdapter != null) {
            mHeaderFooterRecyclerAdapter.removeHeaderView(view);
        }
    }

    /**
     * 移除头部
     *
     * @param viewId 头部ViewId
     */
    public void removeHeaderView(int viewId) {
        if (mHeaderFooterRecyclerAdapter != null) {
            mHeaderFooterRecyclerAdapter.removeHeaderView(viewId);
        }
    }

    /**
     * 添加底部
     *
     * @param view 底部View
     */
    public void addFooterView(View view) {
        if (mHeaderFooterRecyclerAdapter != null) {
            mHeaderFooterRecyclerAdapter.addFooterView(view);
        }
    }

    /**
     * 添加底部
     *
     * @param viewId 底部ViewId
     */
    public void addFooterView(int viewId) {
        if (mHeaderFooterRecyclerAdapter != null) {
            mHeaderFooterRecyclerAdapter.addFooterView(viewId);
        }
    }

    /**
     * 移除底部
     *
     * @param view 底部View
     */
    public void removeFooterView(View view) {
        if (mHeaderFooterRecyclerAdapter != null) {
            mHeaderFooterRecyclerAdapter.removeFooterView(view);
        }
    }

    /**
     * 移除底部
     *
     * @param viewId 底部ViewId
     */
    public void removeFooterView(int viewId) {
        if (mHeaderFooterRecyclerAdapter != null) {
            mHeaderFooterRecyclerAdapter.removeFooterView(viewId);
        }
    }

    /**
     * 设置正在加载的页尾界面
     *
     * @param footerLoadingView 正在加载的页尾界面
     */
    public void setFooterLoadingView(View footerLoadingView) {
        this.mFooterLoadingView = footerLoadingView;
    }

    /**
     * 设置正在加载的页尾界面
     *
     * @param footerLoadingViewId 正在加载的页尾界面Id
     */
    public void setFooterLoadingView(int footerLoadingViewId) {
        this.mFooterLoadingViewId = footerLoadingViewId;
    }

    /**
     * 设置加载完成没有更多数据的页尾界面
     *
     * @param footerLoadEndView 加载完成没有更多数据的页尾界面
     */
    public void setFooterLoadEndView(View footerLoadEndView) {
        this.mFooterLoadEndView = footerLoadEndView;
    }

    /**
     * 设置加载完成没有更多数据的页尾界面
     *
     * @param footerLoadEndViewId 加载完成没有更多数据的页尾界面
     */
    public void setFooterLoadEndView(int footerLoadEndViewId) {
        this.mFooterLoadEndViewId = footerLoadEndViewId;
    }

    /**
     * 刷新显示当前页尾
     *
     * @param end true：无更多数据；false：还有数据待加载
     */
    private void refreshShowFooter(boolean end) {
        View view = end ? mFooterLoadEndView : mFooterLoadingView;
        int viewId = end ? mFooterLoadEndViewId : mFooterLoadingViewId;
        if (getAdapter() instanceof HeaderFooterRecyclerAdapter) {
            ((HeaderFooterRecyclerAdapter) getAdapter()).removeAllFooterView();
            if (view != null) {
                ((HeaderFooterRecyclerAdapter) getAdapter()).addFooterView(view);
            } else if (viewId >= 0) {
                ((HeaderFooterRecyclerAdapter) getAdapter()).addFooterView(viewId);
            }
            getAdapter().notifyDataSetChanged();
        }
    }

    /**
     * 移除所有当前页尾
     */
    private void removeAllFooter() {
        if (getAdapter() instanceof HeaderFooterRecyclerAdapter) {
            ((HeaderFooterRecyclerAdapter) getAdapter()).removeAllFooterView();
            getAdapter().notifyDataSetChanged();
        }
    }

    /**
     * 记录当前显示位置，可以使用{@link RefreshRecyclerView#recoverLastPosition()}恢复到当前位置
     */
    public void recordCurrPosition() {
        if (getAdapter() == null) {
            mFirstVisiblePosition = 0;
            mFirstVisiblePositionOffset = 0;
            return;
        }
        if (getLayoutManager() != null && getLayoutManager() instanceof LinearLayoutManager) {
            LinearLayoutManager linearLayoutManager = (LinearLayoutManager) getLayoutManager();
            mFirstVisiblePosition = linearLayoutManager.findFirstVisibleItemPosition();

            Rect rect = new Rect();
            View firstVisibleView = linearLayoutManager.findViewByPosition(mFirstVisiblePosition);
            mFirstVisiblePositionOffset = firstVisibleView.getTop();
            for (int i = 0; i < getItemDecorationCount(); i++) {
                rect.set(0, 0, 0, 0);
                getItemDecorationAt(i).getItemOffsets(rect, firstVisibleView, this, new State());
                mFirstVisiblePositionOffset -= rect.top;
            }
            mFirstVisiblePositionOffset -= getPaddingTop();
        }
    }

    /**
     * 恢复到上次调用{@link RefreshRecyclerView#recordCurrPosition()}时记录的位置
     */
    public void recoverLastPosition() {
        if (getLayoutManager() != null && getLayoutManager() instanceof LinearLayoutManager) {
            ((LinearLayoutManager) getLayoutManager()).scrollToPositionWithOffset(mFirstVisiblePosition, mFirstVisiblePositionOffset);
        }
    }

    /**
     * 设置条目间距，同时将会移除之前设置的间距，若要设置多个可直接调用{@link #addItemDecoration(ItemDecoration)}
     * <p>可参考使用库中已经封装的两个类：{@link LinearSpacingItemDecoration}，{@link GridSpacingItemDecoration}
     *
     * @param itemDecoration 条目间距封装
     */
    public void setItemSpace(ItemDecoration itemDecoration) {
        for (int i = 0; i < getItemDecorationCount(); i++) {
            removeItemDecorationAt(i);
        }
        addItemDecoration(itemDecoration);
    }

    private AdapterDataObserver mDataObserver = new AdapterDataObserver() {

        @Override
        public void onChanged() {
            if (mAdapter == null) return;
            // 观察者  列表Adapter更新 包裹的也需要更新不然列表的notifyDataSetChanged没效果
            if (mHeaderFooterRecyclerAdapter != mAdapter)
                mHeaderFooterRecyclerAdapter.notifyDataSetChanged();
        }

        @Override
        public void onItemRangeRemoved(int positionStart, int itemCount) {
            if (mAdapter == null) return;
            // 观察者  列表Adapter更新 包裹的也需要更新不然列表的notifyDataSetChanged没效果
            if (mHeaderFooterRecyclerAdapter != mAdapter)
                mHeaderFooterRecyclerAdapter.notifyItemRemoved(positionStart);
        }

        @Override
        public void onItemRangeMoved(int fromPosition, int toPosition, int itemCount) {
            if (mAdapter == null) return;
            // 观察者  列表Adapter更新 包裹的也需要更新不然列表的notifyItemMoved没效果
            if (mHeaderFooterRecyclerAdapter != mAdapter)
                mHeaderFooterRecyclerAdapter.notifyItemMoved(fromPosition, toPosition);
        }

        @Override

        public void onItemRangeChanged(int positionStart, int itemCount) {
            if (mAdapter == null) return;
            // 观察者  列表Adapter更新 包裹的也需要更新不然列表的notifyItemChanged没效果
            if (mHeaderFooterRecyclerAdapter != mAdapter)
                mHeaderFooterRecyclerAdapter.notifyItemChanged(positionStart);
        }

        @Override
        public void onItemRangeChanged(int positionStart, int itemCount, Object payload) {
            if (mAdapter == null) return;
            // 观察者  列表Adapter更新 包裹的也需要更新不然列表的notifyItemChanged没效果
            if (mHeaderFooterRecyclerAdapter != mAdapter)
                mHeaderFooterRecyclerAdapter.notifyItemChanged(positionStart, payload);
        }

        @Override
        public void onItemRangeInserted(int positionStart, int itemCount) {
            if (mAdapter == null) return;
            // 观察者  列表Adapter更新 包裹的也需要更新不然列表的notifyItemInserted没效果
            if (mHeaderFooterRecyclerAdapter != mAdapter)
                mHeaderFooterRecyclerAdapter.notifyItemInserted(positionStart);
        }
    };

    /**
     * 判断是否为顶部或底部
     */
    private OnScrollListener mOnScrollListener = new OnScrollListener() {
        @Override
        public void onScrolled(@NonNull RecyclerView recyclerView, int dx, int dy) {
            super.onScrolled(recyclerView, dx, dy);

        }

        @Override
        public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
            super.onScrollStateChanged(recyclerView, newState);
            if (newState == SCROLL_STATE_IDLE) {
                if (!canScrollVertically(1)) {
                    // 滑动到底部
                    if (mIsLoading) {
                        return;
                    }
                    mIsLoading = true;
                    if (mOnRefreshListener != null) {
                        if (mShowFooter) {
                            refreshShowFooter(false);
                        }
                        if (getAdapter().getItemCount() > 0) {
                            smoothScrollToPosition(getAdapter().getItemCount() - 1);
                        }
                        mOnRefreshListener.onLoadMore();
                    }
                }
                if (!canScrollVertically(-1)) {
                    // 滑动到顶部
                }
            }
        }
    };

    /**
     * 刷新完成，控制页尾显示状态
     *
     * @param end        true：还有待加载数据；false：数据加载完，没有数据了
     * @param showFooter true：显示加载页尾；false：不显示加载页尾
     */
    public void onLoadComplete(boolean end, boolean showFooter) {
        mIsLoading = false;
        mShowFooter = showFooter;
        if (mShowFooter) {
            refreshShowFooter(end);
        } else {
            removeAllFooter();
        }
    }

    /**
     * 设置当需要刷新数据时的监听
     *
     * @param onRefreshListener 当需要刷新数据时的监听
     */
    public void setOnRefreshListener(OnRefreshListener onRefreshListener) {
        mOnRefreshListener = onRefreshListener;
    }

    /**
     * 界面需要加载更多的时候回调
     */
    public interface OnRefreshListener {
        void onLoadMore();
    }

    /**
     * 设置点击回调
     *
     * @param onItemClickListener 点击回调
     */
    public void setOnItemClickListener(OnItemClickListener onItemClickListener) {
        mOnItemClickListener = onItemClickListener;
    }

    /**
     * 内部转换的点击事件
     */
    private OnItemClickListener mInnerOnItemClickListener = new OnItemClickListener() {
        @Override
        public void onClick(View view, int position) {
            if (mOnItemClickListener != null && position >= 0) {
                if (position < mHeaderFooterRecyclerAdapter.getHeaderCount()) {
                    mOnItemClickListener.onHeaderClick(view, position);
                } else if (position < mHeaderFooterRecyclerAdapter.getHeaderCount() + mHeaderFooterRecyclerAdapter.getDataCount()) {
                    position = position - mHeaderFooterRecyclerAdapter.getHeaderCount();
                    if (position >= 0 && position < mHeaderFooterRecyclerAdapter.getDataCount()) {
                        mOnItemClickListener.onClick(view, position);
                    }
                } else if (position < mHeaderFooterRecyclerAdapter.getItemCount()) {
                    position = position - mHeaderFooterRecyclerAdapter.getHeaderCount() - mHeaderFooterRecyclerAdapter.getDataCount();
                    if (position >= 0 && position < mHeaderFooterRecyclerAdapter.getFooterCount()) {
                        mOnItemClickListener.onFooterClick(view, position);
                    }
                }
            }
        }

        @Override
        public void onLongClick(View view, int position) {
            if (mOnItemClickListener != null && position >= 0) {
                if (position < mHeaderFooterRecyclerAdapter.getHeaderCount()) {
                    mOnItemClickListener.onHeaderLongClick(view, position);
                } else if (position < mHeaderFooterRecyclerAdapter.getHeaderCount() + mHeaderFooterRecyclerAdapter.getDataCount()) {
                    position = position - mHeaderFooterRecyclerAdapter.getHeaderCount();
                    if (position >= 0 && position < mHeaderFooterRecyclerAdapter.getDataCount()) {
                        mOnItemClickListener.onLongClick(view, position);
                    }
                } else if (position < mHeaderFooterRecyclerAdapter.getItemCount()) {
                    position = position - mHeaderFooterRecyclerAdapter.getHeaderCount() - mHeaderFooterRecyclerAdapter.getDataCount();
                    if (position >= 0 && position < mHeaderFooterRecyclerAdapter.getFooterCount()) {
                        mOnItemClickListener.onFooterLongClick(view, position);
                    }
                }
            }
        }
    };

    /**
     * 条目拖拽回调
     *
     * @param onItemDragListener 拖拽回调
     */
    public void setOnItemDragListener(OnItemDragListener onItemDragListener) {
        mOnItemDragListener = onItemDragListener;
    }

    private OnItemTouchHelperCallBack mOnItemTouchHelperCallBack = new OnItemTouchHelperCallBack() {
        @Override
        public boolean onMove(@NonNull RecyclerView recyclerView, @NonNull ViewHolder viewHolder, @NonNull ViewHolder target) {
            int innerFrom = viewHolder.getAdapterPosition() - mHeaderFooterRecyclerAdapter.getHeaderCount();
            int innerTo = target.getAdapterPosition() - mHeaderFooterRecyclerAdapter.getHeaderCount();
            boolean result = super.onMove(recyclerView, viewHolder, target);
            if (result && mOnItemDragListener != null) {
                mOnItemDragListener.onDragSort(innerFrom, innerTo);
            }
            return result;
        }
    };
}
